package lumis.doui.source.postloadprocessor;

import lumis.doui.source.ISourceData;
import lumis.doui.source.Source;
import lumis.doui.source.TabularData;
import lumis.portal.PortalException;
import lumis.portal.UnexpectedException;
import lumis.portal.authentication.SessionConfig;
import lumis.portal.el.LumisExpressionEvaluatorImpl;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.serviceinstance.ServiceInstanceConfig;
import lumis.portal.serviceinstance.acl.IServiceInstanceAclManager;
import lumis.portal.serviceinstance.acl.ServiceInstancePermissions;
import lumis.portal.serviceinterface.IServiceInterfaceUrl;
import lumis.util.ITransaction;
import lumis.util.TextUtil;
import lumis.util.XmlUtil;

import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.VariableResolver;

import org.w3c.dom.Node;

/**
 * Post load processor that generates a process action script.
 *
 * @version $Revision: 13092 $ $Date: 2011-05-28 18:19:06 -0300 (Sat, 28 May 2011) $
 * @since 4.2.0
 */
public class RowProcessActionPostLoadProcessor implements IPostLoadProcessor
{
	private final LumisExpressionEvaluatorImpl evaluator = new LumisExpressionEvaluatorImpl();

	@SuppressWarnings("unchecked")
	public void processSource(SessionConfig sessionConfig, Source source, Node parametersNode, ITransaction transaction) throws PortalException
	{
		// validate the preconditions if any
		Node precondition = XmlUtil.selectSingleNode("precondition", parametersNode);
		
		String fieldId = XmlUtil.readNodeString("fieldId", parametersNode);
		if(fieldId == null)
			throw new UnexpectedException("fieldId not specified for the RowLinkPostLoadProcessor");
		
		if(!checkPermissions(parametersNode, source))
			return;
		
		IServiceInterfaceUrl url = source.getDouiContext().getResponse().createActionURL();
		
		String processActionId = XmlUtil.readNodeString("processActionId", parametersNode);
		url.setParameter("doui_processActionId", processActionId);
		Node[] parameters = XmlUtil.selectNodes("addParameters/parameter", parametersNode);
		
		if(url != null)
		{
			TabularData tabularData = (TabularData)source.getData();
			for(ISourceData row : tabularData.getRows())
			{
				if (!checkPreCondition(sessionConfig, row, source, precondition, transaction))
				{
					continue;
				}
				
				for(Node parameter : parameters)
				{
					String name = XmlUtil.readAttributeString("name", parameter);
					String value = row.get(name, String.class);
					
					if(value == null)
						value = "";
					
					url.setParameter(name, value);
				}
				
				StringBuilder script = new StringBuilder();
				String confirmMessage = XmlUtil.readNodeString("confirmMessage", parametersNode);
				if(confirmMessage!= null)
					script.append("if(confirm(\""+TextUtil.escapeJs(ManagerFactory.getLocalizationManager().localize(confirmMessage, source.getDouiContext().getRequest().getServiceInterfaceConfig().getResource()))+"\")) ");
				script.append("window.location.href='"+url.toString()+"';");
				
				row.put(fieldId, script.toString());
			}
		}
	}

	/**
	 * Checks the pre-condition for a row in a source.
	 * 
	 * @param sessionConfig
	 *            the user session config.
	 * @param row
	 *            the row.
	 * @param source
	 *            the source.
	 * @param precondition
	 *            the pre-condition node.
	 * @param transaction
	 *            the transaction.
	 * @return true if pre-condition is satisfied, false otherwise.
	 * @since 6.0.0
	 */
	protected boolean checkPreCondition(SessionConfig sessionConfig, ISourceData row,
			Source<? extends ISourceData> source, Node precondition, ITransaction transaction)
			throws PortalException
	{
		if (precondition == null)
			return true;

		VariableResolver variableResolver = new PostLoadProcessorVariableResolver(row, source);
		String preconditionExpression = precondition.getTextContent();
		try
		{
			return ((Boolean) evaluator.evaluate("${" + preconditionExpression + "}", Boolean.class, variableResolver,
					null)).booleanValue();
		}
		catch (ELException e)
		{
			throw new UnexpectedException(e);
		}
	}

	private boolean checkPermissions(Node parametersNode, Source<?> source) throws PortalException
	{
		boolean allowed = false;
		IServiceInstanceAclManager aclManager = ManagerFactory.getServiceInstanceAclManager();
		ServiceInstanceConfig serviceInstanceConfig = source.getDouiContext().getRequest().getServiceInstanceConfig();
		// if no service instance was provided, skip validation
		if (serviceInstanceConfig == null)
			return true;

		SessionConfig sessionConfig = source.getDouiContext().getRequest().getSessionConfig();

		ServiceInstancePermissions servicePermissions = aclManager.getPermissions(sessionConfig, serviceInstanceConfig.getServiceId(), source.getDouiContext().getTransaction());
		Node[] permissions = XmlUtil.selectNodes("permissions/permission", parametersNode);
		if (permissions.length > 0)
		{
			for (Node permission : permissions)
			{
				String permissionId = XmlUtil.readAttributeString("id", permission);
				if (aclManager.checkPermission(sessionConfig, serviceInstanceConfig.getId(), servicePermissions.valueOf(permissionId), source.getDouiContext().getTransaction()))
				{
					allowed = true;
					break;
				}
			}

			return allowed;
		}
		else
		{
			return true;
		}
	}

}
